﻿using System.ComponentModel;
using System.Reflection;
using Caliburn.Micro;
using SS.WPF.Framework.Localization;
using SS.WPF.Framework.Restriction;

namespace SS.WPF.Toolkit.PropertyEditor
{
    using System;

    /// <summary>
    /// The class implement abstract class PropertyDescriptor to present a Property of a class
    /// <para>
    /// It implements interface IRestrictionContainer to consume instance of IRestriction
    /// </para>
    /// <para>
    /// It implements interface IBindingGroup to consume property ValidationGroup
    /// </para>
    /// </summary>
    public class CustomPropertyDescriptor<T> : PropertyDescriptor, IRestrictionContainer, IBindingGroup
    {
        private readonly PropertyInfo _propertyInfo;

        private readonly Type _propertyType;

        private readonly string _displayName;

        public CustomPropertyDescriptor(string key, PropertyInfo propertyInfo, Type schemasType, IRestriction restriction)
            : this(null, key, propertyInfo, schemasType, restriction)
        {
        }

        public CustomPropertyDescriptor(string displayName, string key, PropertyInfo propertyInfo, Type schemasType,
                                       IRestriction restriction)
            : base(key, null)
        {
            this._displayName = displayName;
            _propertyInfo = propertyInfo;
            _restriction = restriction;
            _propertyType = schemasType ?? this._propertyInfo.PropertyType;
        }

        public override string DisplayName
        {
            get
            {
                if (string.IsNullOrEmpty(this._displayName))
                {
                    return base.DisplayName;
                }

                var msg = IoC.Get<TranslationManager>().Translate(this._displayName);
                return (string)msg;
            }
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override Type ComponentType
        {
            get { return typeof (T); }
        }

        public override string Description
        {
            get
            {
                return string.Format("{0}.Description", this._propertyInfo.Name);
            }
        }

        public override object GetValue(object component)
        {
            var value = _propertyInfo.GetValue(component, null);
            if (!(this._propertyInfo.PropertyType == this._propertyType))
            {
                if (this._propertyInfo.PropertyType == typeof (string))
                {
                    value = Enum.Parse(this._propertyType, (string) value);
                }

                if (this._propertyInfo.PropertyType == typeof (int))
                {
                    value = Enum.ToObject(this._propertyType, (int) value);
                }
            }

            return value;
        }

        public override void SetValue(object component, object value)
        {
            var convertedValue = value;
            if (!(this._propertyInfo.PropertyType == this._propertyType))
            {
                if (this._propertyInfo.PropertyType == typeof (string))
                {
                    convertedValue = value.ToString();
                }

                if (this._propertyInfo.PropertyType == typeof (int))
                {
                    convertedValue = (int) value;
                }
            }

            this._propertyInfo.SetValue(component, convertedValue, null);
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override Type PropertyType
        {
            get { return _propertyType; }
        }

        public override void ResetValue(object component)
        {
            this._propertyInfo.SetValue(component, null, null);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        #region Implementation of IRestrictionContainer

        private readonly IRestriction _restriction;
        public IRestriction Restriction
        {
            get { return this._restriction; }
        }

        #endregion

        #region IBindingGroup

        public string ValidationGroup { get; set; }

        #endregion
    }
}
